/**
  ******************************************************************************
  * @file    eth.c
  * @brief   This file provides code for the configuration
  *          of the ETH instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "eth.h"

/* USER CODE BEGIN 0 */
#include <stdio.h>
#include <string.h>
#include "osal.h"
#include "pcf8574.h"
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
  #pragma data_alignment=4
#endif
__ALIGN_BEGIN ETH_DMADescTypeDef  DMARxDscrTab[ETH_RXBUFNB] __ALIGN_END;/* Ethernet Rx MA Descriptor */

#if defined ( __ICCARM__ ) /*!< IAR Compiler */
  #pragma data_alignment=4
#endif
__ALIGN_BEGIN ETH_DMADescTypeDef  DMATxDscrTab[ETH_TXBUFNB] __ALIGN_END;/* Ethernet Tx DMA Descriptor */

#if defined ( __ICCARM__ ) /*!< IAR Compiler */
  #pragma data_alignment=4
#endif
__ALIGN_BEGIN uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE] __ALIGN_END; /* Ethernet Receive Buffer */

#if defined ( __ICCARM__ ) /*!< IAR Compiler */
  #pragma data_alignment=4
#endif
__ALIGN_BEGIN uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE] __ALIGN_END; /* Ethernet Transmit Buffer */

#define YT8512C_AND_RTL8201BL_PHYREGISTER2      0x0000
#define SR8201F_PHYREGISTER2                    0x001C
#define LAN8720A_PHYREGISTER2                   0x0007
uint32_t PHY_TYPE;
uint16_t ETH_CHIP_PHYSCSR;
uint16_t ETH_CHIP_SPEED_STATUS;
uint16_t ETH_CHIP_DUPLEX_STATUS;
/* USER CODE END 0 */

ETH_HandleTypeDef heth;

/* ETH init function */
void MX_ETH_Init(void)
{

  /* USER CODE BEGIN ETH_Init 0 */

  /* USER CODE END ETH_Init 0 */

  /* USER CODE BEGIN ETH_Init 1 */

  /* USER CODE END ETH_Init 1 */
  heth.Instance = ETH;
  heth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
  heth.Init.Speed = ETH_SPEED_100M;
  heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
  heth.Init.PhyAddress = LAN8742A_PHY_ADDRESS;
  heth.Init.MACAddr[0] =   0x00;
  heth.Init.MACAddr[1] =   0x80;
  heth.Init.MACAddr[2] =   0xE1;
  heth.Init.MACAddr[3] =   0x00;
  heth.Init.MACAddr[4] =   0x00;
  heth.Init.MACAddr[5] =   0x00;
  heth.Init.RxMode = ETH_RXPOLLING_MODE;
  heth.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
  heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;

  /* USER CODE BEGIN MACADDRESS */
  heth.Init.PhyAddress = 0U;
  /* USER CODE END MACADDRESS */

  if (HAL_ETH_Init(&heth) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ETH_Init 2 */
	/* Initialize Tx Descriptors list: Chain Mode */
  HAL_ETH_DMATxDescListInit(&heth, DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);

  /* Initialize Rx Descriptors list: Chain Mode  */
  HAL_ETH_DMARxDescListInit(&heth, DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);

  /* Enable MAC and DMA transmission and reception */
  HAL_ETH_Start(&heth);
  /* USER CODE END ETH_Init 2 */

}

void HAL_ETH_MspInit(ETH_HandleTypeDef* ethHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(ethHandle->Instance==ETH)
  {
  /* USER CODE BEGIN ETH_MspInit 0 */

  /* USER CODE END ETH_MspInit 0 */
    /* ETH clock enable */
    __HAL_RCC_ETH_CLK_ENABLE();

    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOG_CLK_ENABLE();
    /**ETH GPIO Configuration
    PC1     ------> ETH_MDC
    PA1     ------> ETH_REF_CLK
    PA2     ------> ETH_MDIO
    PA7     ------> ETH_CRS_DV
    PC4     ------> ETH_RXD0
    PC5     ------> ETH_RXD1
    PB11     ------> ETH_TX_EN
    PG13     ------> ETH_TXD0
    PG14     ------> ETH_TXD1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
    HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

  /* USER CODE BEGIN ETH_MspInit 1 */
	PhyReset();
  /* USER CODE END ETH_MspInit 1 */
  }
}

void HAL_ETH_MspDeInit(ETH_HandleTypeDef* ethHandle)
{

  if(ethHandle->Instance==ETH)
  {
  /* USER CODE BEGIN ETH_MspDeInit 0 */

  /* USER CODE END ETH_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_ETH_CLK_DISABLE();

    /**ETH GPIO Configuration
    PC1     ------> ETH_MDC
    PA1     ------> ETH_REF_CLK
    PA2     ------> ETH_MDIO
    PA7     ------> ETH_CRS_DV
    PC4     ------> ETH_RXD0
    PC5     ------> ETH_RXD1
    PB11     ------> ETH_TX_EN
    PG13     ------> ETH_TXD0
    PG14     ------> ETH_TXD1
    */
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5);

    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7);

    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_11);

    HAL_GPIO_DeInit(GPIOG, GPIO_PIN_13|GPIO_PIN_14);

  /* USER CODE BEGIN ETH_MspDeInit 1 */

  /* USER CODE END ETH_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
/*  SR8201F     Register 2    0x001C
				Register 3    0xC016

	YT8512C     Register 2    0x0000
				Register 3    0x0128

	LAN8720A    Register 2    0x0007
				Register 3    0xC0F0

	RTL8201BL   Register 2    0x0000
				Register 3    0x8201 */
void PhyReset(void)
{
	uint32_t regvalue;
	HAL_ETH_ReadPHYRegister(&heth,PHY_REGISTER2, &regvalue);//get phy id
	PHY_TYPE = regvalue;
	printf("phy id is %d\n",PHY_TYPE);
	if (PHY_TYPE && 0xFFF == 0xFFF)                           /*LAN8720A*/
    {
        pcf8574_write_bit(ETH_RESET_IO,1);
        osal_usleep(10000);
        pcf8574_write_bit(ETH_RESET_IO,0);
        osal_usleep(10000);
    }
    else                                                    /*YT8512C*/
    {
        pcf8574_write_bit(ETH_RESET_IO,0);
        osal_usleep(10000);
        pcf8574_write_bit(ETH_RESET_IO,1);
        osal_usleep(10000);
    }
	
	HAL_ETH_ReadPHYRegister(&heth,PHY_REGISTER2, &regvalue);//get phy id
	switch (regvalue)
    {
        case YT8512C_AND_RTL8201BL_PHYREGISTER2:
			HAL_ETH_ReadPHYRegister(&heth,PHY_REGISTER3, &regvalue);
    
            if (regvalue == 0x128)
            {
                ETH_CHIP_PHYSCSR  = ((uint16_t)0x11);
                ETH_CHIP_SPEED_STATUS = ((uint16_t)0x4010);
                ETH_CHIP_DUPLEX_STATUS = ((uint16_t)0x2000);
                PHY_TYPE = YT8512C;
            }
            else
            {
                ETH_CHIP_PHYSCSR  = ((uint16_t)0x10);
                ETH_CHIP_SPEED_STATUS = ((uint16_t)0x0022);
                ETH_CHIP_DUPLEX_STATUS = ((uint16_t)0x0004);
                PHY_TYPE = RTL8201;
            }
            break;
        case SR8201F_PHYREGISTER2:
            ETH_CHIP_PHYSCSR  = ((uint16_t)0x00);
            ETH_CHIP_SPEED_STATUS = ((uint16_t)0x2020);
            ETH_CHIP_DUPLEX_STATUS = ((uint16_t)0x0100);
            PHY_TYPE = SR8201F;
            break;
        case LAN8720A_PHYREGISTER2:
            ETH_CHIP_PHYSCSR  = ((uint16_t)0x1F);
            ETH_CHIP_SPEED_STATUS = ((uint16_t)0x0004);
            ETH_CHIP_DUPLEX_STATUS = ((uint16_t)0x0010);
            PHY_TYPE = LAN8720;
            break;
    }
}

int32_t eth_chip_get_link_state(void)
{
    uint32_t readval = 0;
	if (HAL_ETH_ReadPHYRegister(&heth,ETH_CHIP_PHYSCSR, &readval) != HAL_OK)
	{
		return ETH_CHIP_STATUS_READ_ERROR;
	}

    if (((readval & ETH_CHIP_SPEED_STATUS) != ETH_CHIP_SPEED_STATUS) && ((readval & ETH_CHIP_DUPLEX_STATUS) != 0))
    {
        return ETH_CHIP_STATUS_100MBITS_FULLDUPLEX;
    }
    else if (((readval & ETH_CHIP_SPEED_STATUS) != ETH_CHIP_SPEED_STATUS))
    {
        return ETH_CHIP_STATUS_100MBITS_HALFDUPLEX;
    }
    else if (((readval & ETH_CHIP_BCR_DUPLEX_MODE) != ETH_CHIP_BCR_DUPLEX_MODE))
    {
        return ETH_CHIP_STATUS_10MBITS_FULLDUPLEX;
    }
    else
    {
        return ETH_CHIP_STATUS_10MBITS_HALFDUPLEX;
    }
}


int linkState;
int phyEvent;
void PhyEventHandler(void)
{
	uint32_t value;
	//Any link failure condition is latched in the BMSR register. Reading
	//the register twice will always return the actual link status
	HAL_ETH_ReadPHYRegister(&heth, PHY_BSR, &value);/* Read PHY_BSR*/
	HAL_ETH_ReadPHYRegister(&heth, PHY_BSR, &value);/* Read PHY_BSR*/

	//Link is up?
	if((value & PHY_LINKED_STATUS) != 0)
	{
		int32_t readval = 0;
		uint32_t duplex = 0;
		uint32_t speed = 0;
		
		readval = eth_chip_get_link_state();
		if (readval == ETH_CHIP_STATUS_READ_ERROR)
		{
			//Update link state
			linkState = FALSE;
		}
		else
		{
			switch (readval)
			{
				case ETH_CHIP_STATUS_100MBITS_FULLDUPLEX:
					duplex = ETH_MODE_FULLDUPLEX;
					speed = ETH_SPEED_100M;
					printf("ETH_CHIP_STATUS_100MBITS_FULLDUPLEX\n");
					break;
				case ETH_CHIP_STATUS_100MBITS_HALFDUPLEX:
					duplex = ETH_MODE_HALFDUPLEX;
					speed = ETH_SPEED_100M;
					printf("ETH_CHIP_STATUS_100MBITS_HALFDUPLEX\n");
					break;
				case ETH_CHIP_STATUS_10MBITS_FULLDUPLEX:
					duplex = ETH_MODE_FULLDUPLEX;
					speed = ETH_SPEED_10M;
					printf("ETH_CHIP_STATUS_10MBITS_FULLDUPLEX\n");
					break;
				case ETH_CHIP_STATUS_10MBITS_HALFDUPLEX:
					duplex = ETH_MODE_HALFDUPLEX;
					speed = ETH_SPEED_10M;
					printf("ETH_CHIP_STATUS_10MBITS_HALFDUPLEX\n");
					break;
				default:
					duplex = ETH_MODE_FULLDUPLEX;
					speed = ETH_SPEED_100M;
					printf("ETH_CHIP_STATUS_100MBITS_FULLDUPLEX\n");
					break;
			}
			
			heth.Init.Speed = speed;
			heth.Init.DuplexMode = duplex;
			
			//Update link state
			linkState = TRUE;

			/* ETHERNET MAC Re-Configuration */
			HAL_ETH_ConfigMAC(&heth, (ETH_MACInitTypeDef *) NULL);

			/* Restart MAC interface */
			HAL_ETH_Start(&heth);
		}
	}
	else
	{
		//Update link state
		linkState = FALSE;
	}

}
extern int dorun;
void PhyTick(void)
{
	uint32_t value;
	int link;

	//Any link failure condition is latched in the BMSR register. Reading
	//the register twice will always return the actual link status
	HAL_ETH_ReadPHYRegister(&heth, PHY_BSR, &value);/* Read PHY_BSR*/
	HAL_ETH_ReadPHYRegister(&heth, PHY_BSR, &value);/* Read PHY_BSR*/
	
	//Retrieve current link state
	link= (value & PHY_LINKED_STATUS) ? TRUE : FALSE;

    //Link up event?
    if(link && !linkState)
    {
		//Set event flag
		phyEvent = TRUE;
		printf("Link up event\n");
    }
    //Link down event?
    else if(!link && linkState)
    {
		//Set event flag
		phyEvent = TRUE;
		dorun = 0;
		printf("Link down event\n");


    }
}

int EthRdPacket(void* pBuff)
{
    int Len;
    uint8_t* pDmaBuff;
    HAL_StatusTypeDef HalStatus;
	  __IO ETH_DMADescTypeDef *dmarxdesc;
	
    HalStatus = HAL_ETH_GetReceivedFrame(&heth);            // check if a packet has been received
	/* Clean and Invalidate data cache */
	//SCB_CleanInvalidateDCache();
    if (HalStatus == HAL_OK)                                // packet received
    {
        Len = heth.RxFrameInfos.length;                     // packet lenght
        pDmaBuff = (uint8_t*)heth.RxFrameInfos.buffer;      // DMA buffer pointe
        memcpy (pBuff, pDmaBuff, Len);                      // read the data
			
			
		/* Release descriptors to DMA */
		/* Point to first descriptor */
		dmarxdesc = heth.RxFrameInfos.FSRxDesc;
		/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
		for (int i=0; i< heth.RxFrameInfos.SegCount; i++)
		{
			dmarxdesc->Status |= ETH_DMARXDESC_OWN;
			dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
		}

		/* Clear Segment_Count */
		heth.RxFrameInfos.SegCount =0;
		
        return Len;                                         // return the number of bytes read
    }
    else
    {
        return 0;                                        // no packet received
    }
}


int EthWrPacket(void* pBuff, int Len)
{
	uint8_t* pDmaBuff;
	HAL_StatusTypeDef HalStatus;
	/* Clean and Invalidate data cache */
	//SCB_CleanInvalidateDCache();
    if ((heth.TxDesc->Status & ETH_DMATXDESC_OWN) == (uint32_t)RESET)
    {
        pDmaBuff = (uint8_t*)(heth.TxDesc->Buffer1Addr);
        memcpy (pDmaBuff, pBuff, Len);
        HalStatus = HAL_ETH_TransmitFrame(&heth, Len);
        if (HalStatus != HAL_OK)
        {
            printf ("HAL_ETH_TransmitFrame err %d\n", HalStatus);
            return 0;
        }
        return Len;
    }
    else
    {
        return 0;
    }
}
/* USER CODE END 1 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
